# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
 -------------------------------------------------
    File Name:     method_assert.py
    Description:   具体断言逻辑实现
 -------------------------------------------------

 继承 SoftAssert 类，扩展出具体的断言方法。
 如 equal、not_equal、greater_than 等。
 """

from typing import Union, Any

from hellchin.assertion.base_soft_assert import BaseSoftAssert


class AssertMsg:
    """
    AssertMsg 类，用于存储断言信息
    """

    def __init__(self, *args, actual, expected, context):
        """
        AssertMsg 类的构造函数

        :param args: 断言信息
        :param actual: 实际值
        :param expected: 预期值
        :param context: 断言上下文
        """
        self.msg = args[0]
        self.actual = actual
        self.expected = expected
        self.context = context

    def __call__(self, *args, **kwargs):
        """
        __call__ 方法，返回断言信息

        :param args:
        :param kwargs:
        :return: 默认返回第一个参数作为断言信息
        """
        # 对象() 把对象当作函数调用，相当于执行对象.__call__()
        return self.msg  # 默认返回第一个参数作为断言信息


class Undefined:
    """
    Undefined <UNK> 类，用于表示未定义的对象
    """

    def __repr__(self):
        """
        __repr__ 方法，返回字符串 "undefined"
        :return:
        """
        return "undefined"


# 实例化一个特殊对象
UNDEFINED = Undefined()


class AssertionUndefinedError(AssertionError):
    """
    AssertionUndefinedError 类，用于抛出未定义的异常。
    """
    pass


class BaseMethodAssert:
    """
    BaseMethodAssert 类，用于实现具体的断言方法。硬断言方法。
    """

    def __init__(self):
        super().__init__()

        # 判断是否是未定义的对象
        # 在pm断言中，我们使用Box对没有匹配的赋值成了undefined，所以这里需要判断一下
        self.IS_UNDEFINED = None  # 判断是否是未定义的对象

        # 如果不是未定义的对象，则赋值给 expected
        self.expected = None



    # @staticmethod
    # def _parse_assert_data(assert_data: Union[str, dict]) -> dict:
    #     """
    #     解析断言数据，支持字符串或 pydantic 模型
    #
    #     :param assert_data: 可能是字符串表达式或 pydantic 模型
    #     :return: 解析后的 Assertion 对象
    #     """
    #
    #     # 如果断言数据是字典类型
    #     if isinstance(assert_data, dict):  # Assertion
    #         # 直接返回断言数据
    #         return assert_data
    #     # 如果断言数据是字符串类型
    #     elif isinstance(assert_data, str):
    #         # 解析字符串格式，比如 `$.code > "200"`
    #         # return self._parse_string_assert(assert_data)
    #         raise ValueError(f"Unsupported assert_data type: {type(assert_data)}")
    #     else:
    #         raise ValueError(f"Unsupported assert_data type: {type(assert_data)}")

    def _generate_assert_messages(self, success_msg: str, fail_msg: str, actual=None, expected=None) -> tuple:
        """
        生成断言的成功和失败信息。

        :param success_msg: 成功条件描述
        :param fail_msg: 失败消息模板
        :param actual: 实际值
        :param expected: 预期值
        :return: 成功信息和失败信息
        """

        # assert_info_success = success_msg
        fail_msg = fail_msg.format(actual=repr(actual), expected=repr(expected))
        assert_info_fail = f"{success_msg} | AssertionError: {fail_msg}"

        #
        assert_raise_msg = AssertMsg(
            assert_info_fail,
            actual=actual,
            expected=expected,
            context=fail_msg
        )
        # print(f"assert_raise_msg: {assert_raise_msg()}")

        # 如果实际值是未定义的，则抛出 AssertionUndefinedError
        #
        if self.IS_UNDEFINED:
            raise AssertionUndefinedError(assert_raise_msg)  # 抛出一个错误对象，具体的错误信息由 assert_raise_msg 提供

        return success_msg, assert_raise_msg if self.expected else assert_raise_msg # ()

    def equal(self, actual, /, expected=None, *, assert_name=None, jsonpath: str = None):
        """
        判断响应相等的逻辑。
        """

        expected = self.expected or expected

        if expected is None:
            raise ValueError("Expected value cannot be None.")

        success_message, fail_message = self._generate_assert_messages(
            assert_name or f"{repr(expected)} == {jsonpath or actual}",  # repr() 函数返回一个对象的字符串表示形式
            "expected {expected} to deeply equal {actual} ",
            actual, expected
        )

        assert actual == expected, fail_message

        return success_message

    def not_equal(self, actual, expected=None, assert_name=None, jsonpath: str = None):
        """
        判断响应不相等的逻辑。
        """

        expected = self.expected or expected

        if expected is None:
            raise ValueError("Expected value cannot be None.")

        success_message, fail_message = self._generate_assert_messages(
            assert_name or f"{repr(expected)} != {jsonpath or actual}",
            "expected {actual} not to deeply equal {expected} ",
            actual, expected
        )

        assert actual != expected, fail_message

        return success_message

    def greater_than(self, actual, expected=None, assert_name=None, jsonpath: str = None):
        """
        判断响应大于的逻辑。
        """

        expected = self.expected or expected

        if expected is None:
            raise ValueError("Expected value cannot be None.")

        success_message, fail_message = self._generate_assert_messages(
            assert_name or f"{jsonpath or actual} > {repr(expected)}",
            "expected {actual} to be greater than {expected} ",
            actual, expected
        )

        assert actual > expected, fail_message

        return success_message

    def greater_than_or_equal(self, actual, expected=None, *, assert_name=None, jsonpath: str = None) -> None:
        """
        判断响应值是否大于或等于预期值的逻辑。
        """

        expected = self.expected or expected

        if expected is None:
            raise ValueError("Expected value cannot be None.")

        success_message, fail_message = self._generate_assert_messages(
            assert_name or f"{jsonpath or actual} >= {repr(expected)}",
            "expected {actual} to be greater than or equal to {expected} ",
            actual, expected
        )

        assert actual >= expected, fail_message

        return success_message

    def greater_than_or_equal_v2(self, actual, expected=None, *, assert_name=None, jsonpath: str = None) -> None:
        """
        判断响应值是否大于或等于预期值的逻辑。
        """

        expected = self.expected or expected

        if expected is None:
            raise ValueError("Expected value cannot be None.")

        success_message, fail_message = self._generate_assert_messages(
            assert_name or f"{jsonpath or actual} >= {repr(expected)}",
            "expected {actual} to be greater than or equal to {expected} ",
            actual, expected
        )

        assert actual >= expected, fail_message

        return success_message

        # 执行断言并记录结果
        # self.check(actual >= expected, success_message, fail_message)

    def less_than(self, actual, expected=None, *, assert_name=None, jsonpath: str = None) -> None:
        """
        判断响应小于的逻辑。
        """

        expected = self.expected or expected

        if expected is None:
            raise ValueError("Expected value cannot be None.")

        success_message, fail_message = self._generate_assert_messages(
            assert_name or f"{jsonpath or actual} < {repr(expected)}",
            "expected {actual} to be less than {expected} ",
            actual, expected
        )

        assert actual < expected, fail_message

        return success_message

        # 执行断言并记录结果
        # self.check(actual < expected, success_message, fail_message)

    def less_than_or_equal(self, actual, expected=None, *, assert_name=None, jsonpath: str = None) -> None:
        """
        判断响应小于或等于的逻辑。
        """

        expected = self.expected or expected

        if expected is None:
            raise ValueError("Expected value cannot be None.")

        success_message, fail_message = self._generate_assert_messages(
            assert_name or f"{jsonpath or actual} <= {repr(expected)}",
            "expected {actual} to be less than or equal to {expected} ",
            actual, expected
        )

        assert actual <= expected, fail_message

        return success_message

    @property
    def exists(self):
        """
        判断 key 是否存在的逻辑。
        self, expected=None, *, assert_name=None, jsonpath: str = None
        """

        def func(*args, **kwargs):
            print(f"IS_UNDEFINED: {self.IS_UNDEFINED}")

            expected = self.expected or args[0]

            desc = kwargs.get("desc", None)

            if expected is None:
                raise ValueError("Expected value cannot be None.")

            success_message, fail_message = self._generate_assert_messages(
                desc or f"{expected} exists",
                "expected {expected} to exist",
                expected=expected
            )

            assert bool(expected), fail_message

            return success_message

        return func

    @property
    def not_exists(self):
        """
        判断 key 不存在的逻辑。
        """

        def func(*args, **kwargs) -> str:
            expected = self.expected or args[0]

            desc = kwargs.get("desc", None)

            if expected is None:
                raise ValueError("Expected value cannot be None.")

            success_message, fail_message = self._generate_assert_messages(
                desc or f"{expected} does not exist",
                "expected {expected} to not exist",
                expected=expected
            )

            assert not bool(expected), fail_message

            return success_message

        return func


class PmMethodAssert(BaseMethodAssert):
    def __init__(self, expected_value: Any = None):
        super().__init__()

        # 判断是否是未定义的对象
        # 在pm断言中，我们使用Box对没有匹配的赋值成了undefined，所以这里需要判断一下
        self.IS_UNDEFINED = isinstance(expected_value, Undefined)  # 判断是否是未定义的对象

        # 如果不是未定义的对象，则赋值给 expected
        self.expected = expected_value or None


class MethodAssert(BaseSoftAssert):
    def __init__(self, expected_value: Any = None):
        super().__init__()
        self.__base_assert = BaseMethodAssert()
        self.expected = expected_value  # 期望值
        self.results_list = []
        # self.IS_UNDEFINED = False

    def _proxy_method(self, method_name, *args, **kwargs):
        """
        代理方法，用于调用 BaseMethodAssert 中指定方法

        捕获其中的异常
        """
        method = getattr(self.__base_assert, method_name)
        try:
            success_result = method(*args, **kwargs)
            self.results_list.append(self.success_icon + success_result)

        except AssertionError as e:
            self.results_list.append(self.failure_icon + e.args[0]())

    def __getattr__(self, name):
        """
        获取属性时自动调用代理方法

        获取BaseMethodAssert中的方法
        """
        if name.startswith('_'):  # 如果方法名以'_'开头，则不进行代理
            return None
        # 如果存在指定的方法
        elif hasattr(self.__base_assert, name):
            # 返回一个lambda函数，该函数调用指定的方法并传入参数
            return lambda *args, **kwargs: self._proxy_method(name, *args, **kwargs)
        else:
            # 如果没有找到指定的方法，则抛出AttributeError异常
            raise AttributeError(f"{type(self).__name__} object has no attribute {name}")



class MethodSoftAssert(BaseSoftAssert, BaseMethodAssert):
    def __init__(self):
        super().__init__()

        self.expected = None
        self.IS_UNDEFINED = False

    #     self.base_method_assert = BaseMethodAssert()
    #
    # def __get__(self, instance, owner):
    #     # print("instance =", instance, "owner =", owner)
    #     return self.base_method_assert


if __name__ == '__main__':
    """
    存在的问题：
    方法没有检索功能。
    """

    # 以下放最后，因为这里要抛出异常，导致程序终止
    # method_assert = MethodSoftAssert()
    method_assert = MethodAssert()
    method_assert.check(1 == 1)
    method_assert.check(1 == 2)
    method_assert.equal(1, expected=1)
    method_assert.equal(1, expected=2)
    method_assert.fail()
